/**
 * Projekt do předmetu GJA - LATEX TABLE CREATOR
 *
 * Soubor: LatexTableCreatorView.java
 *
 * @author Ondřej Klubal <xkluba00@stud.fit.vutbr.cz>
 * @author Petr Šimon    <xsimon10@stud.fit.vutbr.cz>
 */

package border;

import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;

/**
 * Vylepšený rámeček s individuálním vykreslováním.
 * Vykresluje šedý okraj, vnější rámeček, mezeru, vvnitření rámekček, vnitření okraj
 * Umožňuje definovat sířky jednotlivých rámekčků na každé straně zcela individuálně
 * Dále umožňuje definovat barvy jednotlivých rámečků.
 */
public class LinesBorder extends AbstractBorder implements SwingConstants
{
     protected Color northColor;
     protected Color southColor;
     protected Color eastColor;
     protected Color westColor;
     protected Color gridColor;
     Insets innerBorder;  //vnitřní rámeček
     Insets outerBorder;  //venkovní rámeček
     Insets emptyBorder;  //nejvnitřejší řámeček
     int doubleLineSpace; //nezera mezi doubleline
     
     /**
      * Konstruktor
      * Barva rámečku černá, vnitřní rámeček 1px.
      */
     public LinesBorder()
     {
          this(Color.BLACK, new Insets(1, 1, 1, 1));
     }
     
     /**
      * Konstruktor
      * Vnitřní rámeček 1px.
      * @param color barva rámečku
      */
     public LinesBorder(Color color)
     {
          this(color, new Insets(1, 1, 1, 1));
     }
     
     /**
      * Konstruktor
      * @param color          barva rámečku
      * @param innerBorder    šířka rámečku na včech stanách v px
      */
     public LinesBorder(Color color, int innerBorder)
     {
          this(color, new Insets(innerBorder, innerBorder, innerBorder, innerBorder));
     }
     
     /**
      * Konstruktor
      * @param color          barva rámečku
      * @param innerBorder    šířka rámečku
      */
     public LinesBorder(Color color, Insets innerBorder)
     {
          this.innerBorder = innerBorder;
          northColor = color;
          southColor = color;
          eastColor  = color;
          westColor  = color;
          
          emptyBorder = new Insets(2, 3, 2, 3); //vnitřní, nevykresluje se
          outerBorder = new Insets(0, 0, 0, 0);
          doubleLineSpace = 1; //2px
          gridColor = Color.LIGHT_GRAY;
     }
     
     /**
      * Vykreslí rámeček
      * Nejprve vykreslí mřířku (v pravo da dole, 1px šedá)
      * Vnější řámekček
      * Vnitřní rámeček
      * @param g     Odkaz na <code>Graphics</code>. Vykreslování.
      * @param x     levý horní roh - souřadnice X
      * @param y     levý horní roh - souřadnice Y
      * @param width    šířka
      * @param height   výška
      */
     @Override public void paintBorder(Component c, Graphics g, int x, int y, int width, int height)
     {
          Color oldColor = g.getColor();
          //vykreslíme mřížku
          g.setColor(gridColor);
          g.drawLine(x, y + height - 1, x + width - 1, y + height - 1);
          g.drawLine(x + width - 1, y, x + width - 1, y + height - 1);
          width--;
          height--;
          
          g.setColor(northColor);
          
          for (int i = 0; i < outerBorder.top; i++)
          {
               g.drawLine(x, y + i, x + width - 1, y + i);
          }
          
          g.setColor(eastColor);
          
          for (int i = 0; i < outerBorder.right; i++)
          {
               g.drawLine(x + width - i - 1, y, x + width - i - 1, y + height - 1);
          }
          
          g.setColor(southColor);
          
          for (int i = 0; i < outerBorder.bottom; i++)
          {
               g.drawLine(x, y + height - i - 1, x + width - 1, y + height - i - 1);
          }
          
          g.setColor(westColor);
          
          for (int i = 0; i < outerBorder.left; i++)
          {
               g.drawLine(x + i, y, x + i, y + height - 1);
               
          }
          
          int top    = outerBorder.top;
          int left   = outerBorder.left;
          int bottom = outerBorder.bottom;
          int right  = outerBorder.right;
          
          if (top    != 0) top     += doubleLineSpace;
          
          if (left   != 0) left    += doubleLineSpace;
          
          if (bottom != 0) bottom  += doubleLineSpace;
          
          if (right  != 0) right   += doubleLineSpace;
          
          x       += left;
          y       += top;
          width   -= right + left;
          height  -= bottom + top;
          
          g.setColor(northColor);
          
          for (int i = 0; i < innerBorder.top; i++)
          {
               g.drawLine(x, y + i, x + width - 1, y + i);
          }
          
          g.setColor(eastColor);
          
          for (int i = 0; i < innerBorder.right; i++)
          {
               g.drawLine(x + width - i - 1, y, x + width - i - 1, y + height - 1);
          }
          
          g.setColor(southColor);
          
          for (int i = 0; i < innerBorder.bottom; i++)
          {
               g.drawLine(x, y + height - i - 1, x + width - 1, y + height - i - 1);
          }
          
          g.setColor(westColor);
          
          for (int i = 0; i < innerBorder.left; i++)
          {
               g.drawLine(x + i, y, x + i, y + height - 1);
               
          }
          
          g.setColor(oldColor);
     }
     
     /**
      * Vypočítá rozměry rámečku včetně neviditelných oblastí (pro umístění textu uvnitř atd)
      * @return rozměry rámečku
      */
     public Insets getBorderInsets()
     {
          int top    = 0;
          int left   = 0;
          int bottom = 0;
          int right  = 0;
          
          top     += outerBorder.top;
          left    += outerBorder.left;
          bottom  += outerBorder.bottom;
          right   += outerBorder.right;
          
          if (top    != 0) top     += innerBorder.top + doubleLineSpace;    else top     += innerBorder.top;
          if (left   != 0) left    += innerBorder.left + doubleLineSpace;   else left    += innerBorder.left;
          if (bottom != 0) bottom  += innerBorder.bottom + doubleLineSpace; else bottom  += innerBorder.bottom;
          if (right  != 0) right   += innerBorder.right + doubleLineSpace;  else right   += innerBorder.right;
          
          //invisible border
          top  += emptyBorder.top;
          left += emptyBorder.left;
          bottom += emptyBorder.bottom + 1;
          right += emptyBorder.right + 1;
          
          return new Insets(top, left, bottom, right);
     }
     
     /**
      * Vypočítá rozměry rámečku včetně neviditelných oblastí (pro umístění textu uvnitř atd)
      * @param c konponenta (nevyužito)
      * @return rozměry rámečku
      */
     @Override public Insets getBorderInsets(Component c)
     {
          return getBorderInsets();
     }
     
     /**
      * Vypočítá rozměry rámečku včetně neviditelných oblastí (pro umístění textu uvnitř atd)
      * @param c konponenta (nevyužito)
      * @param insets rozměry (nevyužito) !!!!
      * @return rozměry rámečku
      */
     @Override public Insets getBorderInsets(Component c, Insets insets)
     {
          return getBorderInsets();
     }
     
     /**
      * Rámeček je vždy průhledný !!!
      * @return true
      */
     @Override public boolean isBorderOpaque() { return true; }
     
     /**
      * Nastaví barvu rámečku pro všechny strany
      * @param c Barva rámečku
      */
     public void setColor(Color c)
     {
          northColor = c;
          southColor = c;
          eastColor  = c;
          westColor  = c;
     }
     
     /**
      * Nastaví barvu rámečku na straně definováné směrem.
      * @param c Barva rámečku
      * @param direction směr (NORTH/SOUTH/EAST/WEST)
      */
     public void setColor(Color c, int direction)
     {
          switch (direction)
          {
               case NORTH: northColor = c; break;
               case SOUTH: southColor = c; break;
               case EAST:  eastColor  = c; break;
               case WEST:  westColor  = c; break;
               default:
          }
     }
     
     /**
     * Nastaví šířku vnitřního rámečku v pixelech pro všechny strany
     * @param n šířka
     */
     public void setInnerThickness(int n)
     {
          innerBorder.set(n, n, n, n);
     }
     
     /**
     * Nastaví šířku prázdného (nejvnitřnějšího) rámečku v pixelech pro všechny strany
     * @param n šířka
     */
     public void setEmptyThickness(int n)
     {
          emptyBorder.set(n, n, n, n);
     }
     
     /**
     * Nastaví šířku vnějšího rámečku v pixelech pro všechny strany
     * @param  n šířka
     */
     public void setOuterThickness(int n)
     {
          outerBorder.set(n, n, n, n);
     }
     
     /**
     * Nastaví barvu mřížky
     * @param c Barva rámečku
     */
     public void setGridColor(Color color)
     {
          gridColor = color;
     }
     
     /**
     * Nastaví šířku vnitřního rámečku v pixelech pro všechny strany
     * @param insets šířky
     */
     public void setInnerThickness(Insets insets)
     {
          innerBorder = insets;
     }
     
     /**
      * Nastaví šířku prázdného (nejvnitřnějšího) rámečku v pixelech pro všechny strany
      * @param insets šířky
      */
     public void setEmptyThickness(Insets insets)
     {
          emptyBorder = insets;
     }
     
     /**
      * Nastaví šířku vnějšího rámečku v pixelech pro všechny strany
      * @param insets šířky
      */
     public void setOuterThickness(Insets insets)
     {
          outerBorder = insets;
     }
     
     /**
      * @return rozměry vnitřního rámečku
      */
     public Insets getInnerThickness()
     {
          return new Insets(innerBorder.top, innerBorder.left, innerBorder.bottom, innerBorder.right);
     }
     
     /**
      * @return rozměry vnějšího rámečku
      */
     public Insets getOuterThickness()
     {
          return new Insets(outerBorder.top, outerBorder.left, outerBorder.bottom, outerBorder.right);
     }
     
     /**
     * Nastaví šířku vnitřního rámečku v pixelech na straně definováné směrem.
     * @param n šířka rámečku
     * @param direction směr (NORTH/SOUTH/EAST/WEST)
     */
     public void setInnerThickness(int n, int direction)
     {
          switch (direction)
          {
               case NORTH: innerBorder.top = n; break;
               case SOUTH: innerBorder.bottom = n; break;
               case EAST:  innerBorder.right  = n; break;
               case WEST:  innerBorder.left  = n; break;
               default:
          }
     }
     
     /**
      * Nastaví šířku vnějšího rámečku v pixelech na straně definováné směrem.
       * @param n šířka rámečku
       * @param direction směr (NORTH/SOUTH/EAST/WEST)
      */
     public void setOuterThickness(int n, int direction)
     {
          switch (direction)
          {
               case NORTH: outerBorder.top = n; break;
               case SOUTH: outerBorder.bottom = n; break;
               case EAST:  outerBorder.right  = n; break;
               case WEST:  outerBorder.left  = n; break;
               default:
          }
     }
}
